package scales.utils.collection.path
import scala.collection.immutable.Stack
import scala.collection.IndexedSeqLike
import scala.collection.generic.CanBuildFrom
import scales.utils.collection.Tree
import scales.utils.{PathFoldR, FoldR, LeftLike, deepestLast, top, ItemOrTree, TreeCBF}
sealed trait FoldOperation[Item <: LeftLike[Item, Tree[Item, Section, CC]], Section, CC[X] <: IndexedSeqLike[X, CC[X]]] {
protected def rootChangeAllowed = false
def perform(path: Path[Item, Section, CC]): FoldR[Item, Section, CC]
protected def add(path: Path[Item, Section, CC], direction: Int, newPath: Iterable[ItemOrTree[Item, Section, CC]])(implicit cbf : TreeCBF[Item, Section, CC]) : FoldR[Item, Section, CC] = {
val parent = path.zipUp
if (path.top.isLeft && !rootChangeAllowed)
Right(AddedBeforeOrAfterRoot)
else
Left(parent.
modify { x =>
val tree = x.right.get;
val index = path.node.index + direction
val (pre,pos) = tree.children.splitAt(index)
val newChildren = (pre ++ newPath) ++ pos
Tree(tree.section, newChildren)
})
}
}
case class Remove[Item <: LeftLike[Item, Tree[Item, Section, CC]], Section, CC[X] <: IndexedSeqLike[X, CC[X]]](implicit cbf : TreeCBF[Item, Section, CC]) extends FoldOperation[Item, Section, CC] {
def perform(path: Path[Item, Section, CC]): FoldR[Item, Section, CC] = {
val ores = path.removeAndUp();
if (ores.isDefined) Left(ores.get)
else Right(RemovedRoot)
}
}
case class AddBefore[Item <: LeftLike[Item, Tree[Item, Section, CC]], Section, CC[X] <: IndexedSeqLike[X, CC[X]]](newPath: ItemOrTree[Item, Section, CC])(implicit cbf : TreeCBF[Item, Section, CC]) extends FoldOperation[Item, Section, CC] {
def perform(path: Path[Item, Section, CC]): FoldR[Item, Section, CC] = add(path, 0, List(newPath))
}
case class AddAfter[Item <: LeftLike[Item, Tree[Item, Section, CC]], Section, CC[X] <: IndexedSeqLike[X, CC[X]]](newPath: ItemOrTree[Item, Section, CC])(implicit cbf : TreeCBF[Item, Section, CC]) extends FoldOperation[Item, Section, CC] {
def perform(path: Path[Item, Section, CC]): FoldR[Item, Section, CC] = add(path, 1, List(newPath))
}
case class AsIs[Item <: LeftLike[Item, Tree[Item, Section, CC]], Section, CC[X] <: IndexedSeqLike[X, CC[X]]]() extends FoldOperation[Item, Section, CC] {
def perform(path: Path[Item, Section, CC]): FoldR[Item, Section, CC] = Left(path)
}
object Replace {
def apply[Item <: LeftLike[Item, Tree[Item, Section, CC]], Section, CC[X] <: IndexedSeqLike[X, CC[X]]](replaceWith: ItemOrTree[Item, Section, CC]*)(implicit cbf : TreeCBF[Item, Section, CC]) = new Replace[Item, Section, CC](replaceWith)
}
case class Replace[Item <: LeftLike[Item, Tree[Item, Section, CC]], Section, CC[X] <: IndexedSeqLike[X, CC[X]]](replaceWith: Iterable[ItemOrTree[Item, Section, CC]])(implicit cbf : TreeCBF[Item, Section, CC]) extends FoldOperation[Item, Section, CC] {
override def rootChangeAllowed = true
def perform(path: Path[Item, Section, CC]): FoldR[Item, Section, CC] = {
val tpath = path.modify(_ => replaceWith.head)
add(tpath, 1, replaceWith.tail)
}
}
case class ReplaceWith[Item <: LeftLike[Item, Tree[Item, Section, CC]], Section, CC[X] <: IndexedSeqLike[X, CC[X]]](f: PathFoldR[Item, Section, CC], wholeTree : Boolean = false)(implicit cbf : TreeCBF[Item, Section, CC]) extends FoldOperation[Item, Section, CC] {
def perform(path: Path[Item, Section, CC]): FoldR[Item, Section, CC] =
f( if (wholeTree)
path
else
top(path.tree) ).
fold(fres =>
Left(path.modify(_ =>
fres.tree
)),
x => {
if ((x eq RemovedRoot) &&
(!wholeTree))
Remove().perform(path)
else
Right(x)})
}
sealed trait FoldError
case object NoPaths extends FoldError
case object NoSingleRoot extends FoldError
case object RemovedRoot extends FoldError
case object AddedBeforeOrAfterRoot extends FoldError